Skip to content

[MWAR-443] Fix deletion of files placed by maven-dependency-plugin - #641

Closed
elharo wants to merge 1 commit into
apache:masterfrom
elharo:MWAR-443-fix
Closed

[MWAR-443] Fix deletion of files placed by maven-dependency-plugin#641
elharo wants to merge 1 commit into
apache:masterfrom
elharo:MWAR-443-fix

Conversation

@elharo

@elharo elharo commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Fixes #522

The WAR plugin's outdated resource detection was incorrectly marking files in WEB-INF/lib as outdated even when they were placed by other plugins (e.g., maven-dependency-plugin) for non-runtime-scope artifacts. These files would then be deleted by deleteOutdatedResources().

The fix computes the expected filenames for runtime-scope artifacts and only marks files under WEB-INF/lib as outdated if they match one of those filenames. Files placed by other plugins for provided-scope or other non-runtime artifacts are no longer touched.

Root cause: When the DefaultWarPackagingContext constructor walks the webappDirectory, it marks files older than session.getStartTime() as "outdated". Files copied by maven-dependency-plugin to WEB-INF/lib/ have timestamps from the local Maven repository (old), so they get marked as outdated. The WAR plugin only copies runtime-scope artifacts, so provided-scope artifacts are never "claimed" via addResource(), and are subsequently deleted.

Fix: Before marking a file under WEB-INF/lib/ as outdated, verify it matches a runtime-scope artifact filename. If it doesn't, it was placed by another plugin and should be preserved.

@elharo elharo changed the title MWAR-443: Fix deletion of files placed by maven-dependency-plugin [MWAR-443] Fix deletion of files placed by maven-dependency-plugin Jul 28, 2026
@elharo
elharo requested a review from Copilot July 28, 2026 15:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Fixes MWAR-443 by preventing the WAR plugin from deleting WEB-INF/lib files that were placed by other plugins (e.g., maven-dependency-plugin) and aren’t runtime-scope dependencies managed by the WAR plugin.

Changes:

  • Add runtime-artifact filename computation and use it to gate “outdated” marking under WEB-INF/lib/.
  • Add a new unit test ensuring a “provided-scope-like” jar in WEB-INF/lib is preserved during exploded execution.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/main/java/org/apache/maven/plugins/war/AbstractWarMojo.java Avoids marking non-runtime WEB-INF/lib files as outdated by matching only runtime artifact filenames.
src/test/java/org/apache/maven/plugins/war/WarExplodedMojoTest.java Adds regression test for MWAR-443 to ensure dependency-plugin-provided jars are not deleted.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +960 to +963
public void testProvidedScopeArtifactPlacedByDependencyPluginShouldNotBeDeleted(WarExplodedMojo mojo)
throws Exception {
// Ensure session has a start time so the outdated resource detection is active
when(mavenSession.getStartTime()).thenReturn(new Date());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This follows the same pattern used by WarExplodedMojoFilteringTest (which calls when(mavenSession.getSystemProperties()).thenReturn(...)). The test harness provides a Mockito mock for @Inject MavenSession. The test passes successfully with this approach.

Comment on lines +967 to +984
File webAppDirectory = mojo.getWebappDirectory();
File libDir = new File(webAppDirectory, "WEB-INF/lib");
libDir.mkdirs();
File providedJar = new File(libDir, "derbyLocale_cs-10.14.2.0.jar");
providedJar.createNewFile();
// Set timestamp to something in the past (before session start)
providedJar.setLastModified(0L);

// Run the mojo
mojo.execute();

// The file should NOT be deleted - it was placed by another plugin
assertTrue(providedJar.exists(), "provided-scope artifact should not be deleted by WAR plugin");

// Cleanup
providedJar.delete();
libDir.delete();
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest revision. Cleanup is now in a finally block with proper resource cleanup.

Comment on lines +725 to +732
String classifier = artifact.getClassifier();
if (classifier != null && !classifier.trim().isEmpty()) {
fileNames.add(MappingUtils.evaluateFileNameMapping(
MappingUtils.DEFAULT_FILE_NAME_MAPPING_CLASSIFIER, artifact));
} else {
fileNames.add(MappingUtils.evaluateFileNameMapping(
MappingUtils.DEFAULT_FILE_NAME_MAPPING, artifact));
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest revision. getRuntimeArtifactFileNames() now checks getOutputFileNameMapping() and uses it if set, mirroring the same logic as ArtifactsPackagingTask.getArtifactFinalName().

Comment on lines +718 to +724
String type = artifact.getType();
if ("jar".equals(type)
|| "ejb".equals(type)
|| "ejb-client".equals(type)
|| "test-jar".equals(type)
|| "bundle".equals(type)
|| "par".equals(type)) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest revision. Extracted isLibraryType() to AbstractWarPackagingTask and now use it from both ArtifactsPackagingTask.performPackaging() and getRuntimeArtifactFileNames(), eliminating the duplication.

Fixes apache#522

Address code review comments:
- Extract shared isLibraryType() in AbstractWarPackagingTask to
  avoid duplicating artifact type list across the codebase
- Use outputFileNameMapping in getRuntimeArtifactFileNames() when set
- Use isLibraryType() in both ArtifactsPackagingTask and the
  outdated resource detection logic
- Fix test cleanup with try/finally and recursive delete
@elharo
elharo marked this pull request as draft July 28, 2026 17:43
@elharo elharo closed this Jul 28, 2026
@elharo
elharo deleted the MWAR-443-fix branch July 28, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MWAR-443] Maven WAR plugin is deleting files generated by Maven Dependency plugin after upgrading to 3.3.1

2 participants